package cn.pconline.autoclub.service;

import cn.pconline.autoclub.entity.ClubPv;
import cn.pconline.autoclub.util.DateUtils;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.danga.MemCached.MemCachedClient;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.apache.commons.lang.StringUtils;
import org.gelivable.dao.GeliDao;
import org.gelivable.dao.GeliOrm;
import org.gelivable.dao.SqlBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.dao.EmptyResultDataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.ResultSetExtractor;

/**
 * 车友会首页pv统计service
 *
 * @author fgs
 */
public class ClubPvService {

    @Autowired
    GeliDao geliDao;
    @Autowired
    JdbcTemplate jdbcTemplate;
    @Autowired
    MemCachedClient mcc;
    @Autowired
    GeliOrm geliOrm;
    private static final HashMap<Integer, String> weekStr = new HashMap<Integer, String>();

    static {
        weekStr.put(1, "周日");
        weekStr.put(2, "周一");
        weekStr.put(3, "周二");
        weekStr.put(4, "周三");
        weekStr.put(5, "周四");
        weekStr.put(6, "周五");
        weekStr.put(7, "周六");
    }
    private static final Logger log = LoggerFactory.getLogger(ClubPvService.class);

    /**
     * 更新PV，每次+1
     *
     * @param clubId
     * @param ymd
     * @return
     */
    public boolean savePv(long clubId, int ymd) {
        Date now = new Date();
        SqlBuilder sql = new SqlBuilder();
        sql.appendSql("insert into ").appendSql(geliOrm.getTableName(ClubPv.class, clubId)).appendSql(" ( club_id,ymd,pv,create_at,update_at ) values(")
                .appendValue(clubId).appendSql(",")
                .appendValue(ymd).appendSql(",")
                .appendValue(1).appendSql(",")
                .appendValue(now).appendSql(",")
                .appendValue(now).appendSql(" ) on duplicate key update update_at = ").appendValue(now).appendSql(",pv=pv+1");
        try {
            return jdbcTemplate.update(sql.getSql(), sql.getValues()) > 0;
        } catch (EmptyResultDataAccessException e) {
            return false;
        }
    }

    /**
     * 根据车友会获得总pv数
     *
     * @param clubId
     * @return
     */
    public int countPvByClubId(long clubId) {
        SqlBuilder sql = new SqlBuilder();
        sql.appendSql(" select sum(pv) from ").appendSql(geliOrm.getTableName(ClubPv.class, clubId));
        sql.appendSql(" where club_id = ").appendValue(clubId);
        try {
            return geliDao.count(sql.getSql(), sql.getValues());
        } catch (EmptyResultDataAccessException e) {
            log.error("Exception :", e);
        }
        return 0;
    }

    /**
     * 获取车友会某天的PV数
     *
     * @param clubId
     * @return
     */
    public int countPvByClubId(long clubId, int ymd) {
        SqlBuilder sql = new SqlBuilder();
        sql.appendSql(" select sum(pv) from ").appendSql(geliOrm.getTableName(ClubPv.class, clubId));
        sql.appendSql(" where club_id = ").appendValue(clubId).appendSql(" and ymd = ").appendValue(ymd);
        try {
            return geliDao.count(sql.getSql(), sql.getValues());
        } catch (EmptyResultDataAccessException e) {
            log.error("Exception :", e);
        }
        return 0;
    }

    private JSONObject toJSONObject(ClubPv pv) {
        Calendar c = Calendar.getInstance();
        c.setTime(pv.getCreateAt());
        int k = c.get(Calendar.DAY_OF_WEEK);
        JSONObject o = new JSONObject();
        o.put("name", weekStr.get(k));
        o.put("value", pv.getPv());
        return o;
    }

    private JSONArray toJSONArray(List<ClubPv> list) {
        JSONArray a = new JSONArray();
        for (ClubPv pv : list) {
            a.add(toJSONObject(pv));
        }
        return a;
    }

    /**
     * 根据车友会获取几天内的所有pv值 （查多少天，会返回多少天的对象）
     *
     * @param clubId
     * @param day
     * @return
     */
    public JSONArray getClubPvsByDays(long clubId, int day) {
        day = day - 1;//排除掉今天
        Date yesterday = DateUtils.getYesterday();
        Date startDate = DateUtils.getSingleDateBefore(yesterday, day);
        //算出要查询的数据日期范围
        int start = DateUtils.formatData2YMD(startDate);
        int end = DateUtils.formatData2YMD(yesterday);
        String key = "ClubPvList-" + clubId + "-" + start + "-" + end;
        String jsonStr = (String) mcc.get(key);
        JSONArray clubPvArr = null;
        if (StringUtils.isNotEmpty(jsonStr)) {
            clubPvArr = JSONArray.parseArray(jsonStr);
        }
        if (clubPvArr == null) {
            List<ClubPv> pvs = getClubPvsByDay(clubId, start, end);
            //查询到的数据小于要查的天数,说明其中有没有数据的天数,需要补空
            if (pvs.size() < day) {
                List<ClubPv> list = new ArrayList<ClubPv>(day);
                //把查询到的数据转为map
                Map<Integer, ClubPv> pvMap = parseListToMap(pvs);
                for (int i = 0; i < day; i++) {
                    //从第一天开始补起
                    Date date = DateUtils.getDateAfter(startDate, i + 1);
                    int current = DateUtils.formatData2YMD(date);
                    //当天没数据补空
                    ClubPv clubPv = pvMap.get(current);
                    if (clubPv == null) {
                        clubPv = new ClubPv();
                        clubPv.setClubId(clubId);
                        clubPv.setYmd(DateUtils.formatData2YMD(date));
                        clubPv.setPv(0);
                        clubPv.setCreateAt(date);
                        clubPv.setUpdateAt(date);
                    }
                    list.add(clubPv);
                }
                clubPvArr = toJSONArray(list);
            } else {
                clubPvArr = toJSONArray(pvs);
            }
        }
        //先缓存到昨天
        mcc.add(key, clubPvArr.toJSONString());
        int todayPv = countPvByClubId(clubId, DateUtils.getTodayYmd());
        ClubPv pv = new ClubPv();
        pv.setClubId(clubId);
        pv.setCreateAt(DateUtils.getNow());
        pv.setUpdateAt(DateUtils.getNow());
        pv.setPv(todayPv);
        pv.setYmd(DateUtils.getTodayYmd());
        clubPvArr.add(toJSONObject(pv));
        return clubPvArr;
    }

    /**
     * List转为Map
     *
     * @param list
     * @return
     */
    private Map<Integer, ClubPv> parseListToMap(List<ClubPv> list) {
        Map<Integer, ClubPv> map = new HashMap<Integer, ClubPv>();
        if (list != null && !list.isEmpty()) {
            for (ClubPv clubPv : list) {
                map.put(clubPv.getYmd(), clubPv);
            }
        }
        return map;
    }

    /**
     * 获取指定时间段内的PV量（没有缓存，需要外部自己缓存）
     *
     * @param clubId
     * @param start
     * @param end
     * @return
     */
    private List<ClubPv> getClubPvsByDay(long clubId, int start, int end) {
        SqlBuilder sql = new SqlBuilder();
        sql.appendSql("select * from ").appendSql(geliOrm.getTableName(ClubPv.class, clubId)).appendSql(" where club_id=").appendValue(clubId).appendSql(" and ymd>").appendValue(start).appendSql(" and ymd<=").appendValue(end);
        List<ClubPv> list = jdbcTemplate.query(sql.getSql(), sql.getValues(), new ResultSetExtractor<List<ClubPv>>() {
            @Override
            public List<ClubPv> extractData(ResultSet rs) throws SQLException, DataAccessException {
                List<ClubPv> list = new ArrayList();
                while (rs.next()) {
                    ClubPv pv = new ClubPv();
                    pv.setClubId(rs.getLong("club_id"));
                    pv.setCreateAt(rs.getTimestamp("create_at"));
                    pv.setPv(rs.getInt("pv"));
                    pv.setUpdateAt(rs.getTimestamp("update_at"));
                    pv.setYmd(rs.getInt("ymd"));
                    list.add(pv);
                }
                return list;
            }
        });
        return list;
    }
}
